using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;


namespace HEFramework
{
    /// <summary>
    ///
    /// 数据表格加载器
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2024-01-17 20:55:27
    /// ----------------------------------------
    /// </summary>
    public class DataTableLoader : Singleton<DataTableLoader>, ISingletonAwake
    {
        /// <summary>
        /// 资源加载路径
        /// </summary>
        private string dataCodePrefix = "DR";

        /// <summary>
        /// table字典
        /// </summary>
        /// <returns></returns>
        private Dictionary<Type, DataTableBase> tables = new();

        private Dictionary<string, string> langs = new();

        private DataTableSettingScriptableObject data = DataTableSettingScriptableObject.Instance;

        private Assets assets;


        public void Awake()
        {
            assets = AssetLoader.Instance.GetAssets();
        }

        protected override void Destroy()
        {
            tables.Clear();
            langs.Clear();
            assets.Dispose();
        }


        /// <summary>
        /// 加载初始化本地化字典
        /// </summary>
        /// <param name="_langName"></param>
        /// <returns></returns>
        public bool LoadLocalizationDic(string _langName)
        {
            langs.Clear();
            string curTextPath = data.SaveOutputKeyPath.Replace("Assets/AssetBundles/", "").Replace("Assets/Resources/", "");
            TextAsset textAsset = assets.LoadAssetSyn<TextAsset>(curTextPath, _langName, ResourceConfig.Extension.TXT);
            return XmlUtils.ParseDictionary(textAsset.text, langs);
        }

        /// <summary>
        /// 加载表格资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public DataTable<T> LoadDataTable<T>() where T : IData
        {
            Type type = typeof(T);
            var t = GetDataTable<T>();
            if (t != null)
            {
                return t;
            }
            else
            {
                LoadDataTable(type);
                return GetDataTable<T>();
            }
        }

        /// <summary>
        /// 获取表格资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public DataTable<T> GetDataTable<T>() where T : IData
        {
            Type type = typeof(T);
            return GetDataTable(type) as DataTable<T>;
        }

        /// <summary>
        /// 获取本地化后的值
        /// </summary>
        /// <param name="_key"></param>
        /// <returns></returns>
        public string GetLocalizationString(string _key)
        {
            string value = "";
            if (!langs.TryGetValue(_key, out value))
            {
                value = "No-key-" + _key;
            }

            return value;
        }

        /// <summary>
        /// 加载表格资源
        /// </summary>
        /// <param name="_type"></param>
        /// <returns></returns>
        private bool LoadDataTable(Type _type)
        {
            string fileName = _type.Name;
            fileName = fileName.Substring(dataCodePrefix.Length, fileName.Length - dataCodePrefix.Length);
            string curTextPath = data.SaveDataPath.Replace("Assets/AssetBundles/", "").Replace("Assets/Resources/", "");
            TextAsset textAsset = assets.LoadAssetSyn<TextAsset>(curTextPath, fileName, ResourceConfig.Extension.TXT);
            return LoadDataTable(_type, textAsset);
        }

        /// <summary>
        /// 加载资源
        /// </summary>
        /// <returns></returns>
        private bool LoadDataTable(Type _dataType, TextAsset _textAsset)
        {
            if (_dataType == null)
            {
                Log.Error("LoadDataTable Error.dataType = null");
                return false;
            }

            if (_textAsset == null)
            {
                Log.Error("LoadDataTable Error.textAsset = null");
                return false;
            }

            // 获取构造函数
            Type[] constructorParamTypes = new Type[0];
            object[] constructorParam = new Type[0];
            ConstructorInfo info = _dataType.GetConstructor(constructorParamTypes);
            if (info == null)
            {
                Log.Error("LoadDataTable Error.info = null");
                return false;
            }

            // 获取表格
            Type tableBaseType = typeof(DataTable<>);
            Type tableType = tableBaseType.MakeGenericType(new Type[] { _dataType });
            DataTableBase table = tableType.GetConstructors()?[0].Invoke(constructorParam) as DataTableBase;
            if (table == null)
            {
                Log.Error("LoadDataTable Error.table = null");
                return false;
            }

            // 解析数据
            table.Init(_dataType.Name, _dataType, ParseData(_dataType, info, _textAsset));
            tables.Add(_dataType, table);
            return true;
        }

        /// <summary>
        /// 解析数据为字典Dictionary<int,type>
        /// </summary>
        /// <param name="_type"></param>
        /// <param name="_info"></param>
        /// <param name="_textAsset"></param>
        /// <returns></returns>
        private object ParseData(Type _type, ConstructorInfo _info, TextAsset _textAsset)
        {
            string text = _textAsset.text.Replace("\r\n", "\n");
            text = text.TrimEnd('\n');
            string[] dataLines = text.Split('\n');
            Type[] dicType = new Type[] { typeof(int), _type };
            object[] dicAddParams = new object[2];

            Type tableType = typeof(Dictionary<,>).MakeGenericType(dicType);
            MethodInfo tryAddInfo = tableType.GetMethod("TryAdd", dicType);
            object dataDic = Activator.CreateInstance(tableType) as object;
            object[] constructorParam = new Type[0];
            IData data;
            for (int i = 0; i < dataLines.Length; i++)
            {
                // 解析
                data = (IData)_info.Invoke(constructorParam);
                data.ParseDataRow(dataLines[i]);
                // 加入字典中
                dicAddParams[0] = data.ID;
                dicAddParams[1] = data;
                bool flag = (bool)tryAddInfo.Invoke(dataDic, dicAddParams);
                if (!flag)
                {
                    Debug.LogErrorFormat("LoadDataTable Error:There is a duplicate id. typeName:{0},data.Id:{1}.", _type.Name, data.ID);
                }
            }

            return dataDic;
        }

        /// <summary>
        /// 获取配表Table
        /// </summary>
        /// <param name="_type"></param>
        /// <returns></returns>
        private DataTableBase GetDataTable(Type _type)
        {
            tables.TryGetValue(_type, out DataTableBase table);
            return table;
        }
    }
}